package lmscript.postscript.io;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;

public class ASCIIHexInputStream extends InputStream {
	public static final char EOD = '>';

	private InputStream in;
	private int line;

	public ASCIIHexInputStream(InputStream in) {
		super();
		this.in = in;
	}

	@Override
	public int read() throws IOException {
		int b1 = this.readHexDigit();
		if (b1 == -1) {
			throw new IOException("hex input length is zero!");
		}
		int b2 = this.readHexDigit();
		if (b2 == -1) {
			b2 = 0;
		}

		return (b1 << 4 | b2) & 0xFF;
	}

	public int lineCount() {
		return this.line;
	}

	private int readHexDigit() throws IOException {
		int c = -1;
		int last = -1;
		while (true) {
			c = this.in.read();
			switch (c) {
			case -1:
				throw new EOFException("unexpected EOF!");
			case EOD: {
				line++;
				return -1;
			}
			case '\r': {
				line++;
				last = c;
				break;
			}
			case '\n': {
				if (last != '\r') {
					line++;
				}
				last = c;
				break;
			}
			case 0x00:
			case ' ':
			case '\t':
			case '\f': {
				last = c;
				break;
			}
			case '0':
				return 0;
			case '1':
				return 1;
			case '2':
				return 2;
			case '3':
				return 3;
			case '4':
				return 4;
			case '5':
				return 5;
			case '6':
				return 6;
			case '7':
				return 7;
			case '8':
				return 8;
			case '9':
				return 9;
			case 'a':
			case 'A':
				return 10;
			case 'b':
			case 'B':
				return 11;
			case 'c':
			case 'C':
				return 12;
			case 'd':
			case 'D':
				return 13;
			case 'e':
			case 'E':
				return 14;
			case 'f':
			case 'F':
				return 15;
			default:
				throw new EOFException("unexpected character: " + c);
			}
		}
	}
}
